﻿/***********************************************************************
 * <copyright file="ActionSecurityService.svc.cs" company="B/S JSC">
 * -->    Copyright (C) statement. All right reserved
 * </copyright>
 * 
 * Created:   Hoang Bich Son 
 * Email:    sonhb@newman.vn
 * Website:
 * Create Date: Friday, March 14, 2014
 * Usage: 
 * 
 * RevisionHistory: 
 * Date         Author               Description 
 * 
 * ************************************************************************/

using System;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Web.Security;
using DataSecurity;
using DataSecurity.StandartInterfaces;
using Encryption;
using SecurityService.DataTransferObjectMapper;
using SecurityService.MessageBase;
using SecurityService.Messages;
using WebMatrix.WebData;

namespace SecurityService
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ActionSecurityService" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select ActionSecurityService.svc or ActionSecurityService.svc.cs at the Solution Explorer and start debugging.         
    /// <summary>
    /// 
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ActionSecurityService : IActionSecurityService
    {
        #region Parameter
        /// <summary>
        /// The site DAO
        /// </summary>
        private static readonly ISite SiteDao = DataAccess.SiteDao;

        /// <summary>
        /// The permission DAO
        /// </summary>
        private static readonly IPermission PermissionDao = DataAccess.PermissionDao;

        /// <summary>
        /// The role DAO
        /// </summary>
        private static readonly IRole RoleDao = DataAccess.RoleDao;

        /// <summary>
        /// The role in site DAO
        /// </summary>
        private static readonly IRoleInSite RoleInSiteDao = DataAccess.RoleInSiteDao;

        /// <summary>
        /// The permission in site DAO
        /// </summary>
        private static readonly IPermissionInSite PermissionInSiteDao = DataAccess.PermissionInSiteDao;

        /// <summary>
        /// The user DAO
        /// </summary>
        private static readonly IUser UserDao = DataAccess.UserDao;

        // Session state variables
        /// <summary>
        /// The _access token
        /// </summary>
        private static string _accessToken;

        /// <summary>
        /// The _user name
        /// </summary>
        private static string _userName;
        #endregion

        #region Validate


        /// <summary>
        /// Gets unique session based token that is valid for the duration of the session.
        /// </summary>
        /// <param name="request">Token request message.</param>
        /// <returns>
        /// Token response message.
        /// </returns>
        public TokenResponse GetToken(TokenRequest request)
        {
            var response = new TokenResponse(request.RequestId);

            // Validate client tag only
            if (!ValidRequest(request, response, Validate.ClientTag))
                return response;

            // Note: these are session based and expire when session expires.
            _accessToken = Guid.NewGuid().ToString();
            //_shoppingCart = new ShoppingCart(_defaultShippingMethod);

            response.AccessToken = _accessToken;
            return response;
        }

        /// <summary>
        /// Validate 3 security levels for a request: ClientTag, AccessToken, and User Credentials
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="response">The response message.</param>
        /// <param name="validate">The validation that needs to take place.</param>
        /// <returns></returns>
        private bool ValidRequest(RequestBase request, ResponseBase response, Validate validate)
        {
            // Validate Client Tag. 
            // Hardcoded here. In production this should query a 'client' table in a database.
            if ((Validate.ClientTag & validate) == Validate.ClientTag)
            {
                if (request.ClientTag != "ABC123")
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = "Unknown Client Tag";
                    return false;
                }
            }
            // Validate access token
            if ((Validate.AccessToken & validate) == Validate.AccessToken)
            {
                if (request.AccessToken != _accessToken)
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = "Invalid or expired AccessToken. Call GetToken()";
                    return false;
                }
            }
            // Validate user credentials
            if ((Validate.UserCredentials & validate) == Validate.UserCredentials)
            {
                if (_userName == null)
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = "Please login and provide user credentials before accessing these methods.";
                    return false;
                }
            }
            return true;
        }
        #endregion

        #region Authentication

        /// <summary>
        /// Login to application service.
        /// </summary>
        /// <param name="request">Login request message.</param>
        /// <returns>
        /// Login response message.
        /// </returns>
        public LoginResponse Login(LoginRequest request)
        {
            var response = new LoginResponse(request.RequestId);
            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;
            try
            {

                if (!@WebSecurity.Initialized)
                    WebSecurity.InitializeDatabaseConnection("ADO.NET.SqlServer", "UserProfile", "UserId", "UserName", true);
                if (!Membership.ValidateUser(request.UserName, request.Password))
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = ErrorCode.Invalid.ToString();
                    return response;
                }
                var user = UserDao.GetUser(WebSecurity.GetUserId(request.UserName));
                if (user.IsActive)
                {
                    response.Acknowledge = AcknowledgeType.Success;
                    response.UserId = user.UserId;
                    response.UnitId = user.UnitId;
                }
                else
                {
                    response.Message = ErrorCode.NotActive.ToString();
                    response.Acknowledge = AcknowledgeType.Failure;
                    return response;
                }
                _userName = request.UserName;
            }
            catch (Exception e)
            {
                response.Acknowledge = AcknowledgeType.Failure;
                response.Message = e.Message;
                return response;
            }

            return response;
        }

        /// <summary>
        /// Logout from application service.
        /// </summary>
        /// <param name="request">Logout request message.</param>
        /// <returns>
        /// Login request message.
        /// </returns>
        public LogoutResponse Logout(LogoutRequest request)
        {
            var response = new LogoutResponse(request.RequestId);

            // Validate client tag and access token
            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            _userName = null;

            return response;
        }
        #endregion

        #region Site

        /// <summary>
        /// Gets the sites.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public SiteResponse GetSites(SiteRequest request)
        {
            var response = new SiteResponse(request.RequestId);
            var criteria = request.Criteria;
            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;
            if (request.LoadOptions.Contains("Sites"))
            {
                if (request.OptionTypes == OptionType.IsPaging)
                {
                    var totalPage = request.TotalPage;
                    var objs = SiteDao.GetPaged(request.CurrentPage, ref totalPage);
                    response.TotalPage = totalPage;
                    response.Sites = Mapper.ToDataTransferObjects(objs);
                }
                else
                {
                    var objs = SiteDao.GetList();
                    response.Sites = Mapper.ToDataTransferObjects(objs);
                }
            }
            if (request.LoadOptions.Contains("Search"))
            {
                var totalPage = request.TotalPage;
                var objs = SiteDao.GetAdvanced(criteria.Keyword, criteria.Status, criteria.SortExpression, criteria.OrderExpression, request.CurrentPage, ref totalPage);
                response.TotalPage = totalPage;
                response.Sites = Mapper.ToDataTransferObjects(objs);
            }
            if (request.LoadOptions.Contains("Site"))
            {
                var obj = SiteDao.Get(criteria.Id);
                response.Site = Mapper.ToDataTransferObject(obj);
            }
            if (request.LoadOptions.Contains("SitesByParentId"))
            {
                var objs = SiteDao.GetListByParentId(criteria.ParentId);
                response.Sites = Mapper.ToDataTransferObjects(objs);
            }
            if (request.LoadOptions.Contains("SitesByUser"))
            {
                var objs = SiteDao.GetList(criteria.UserId, criteria.ParentId);
                response.Sites = Mapper.ToDataTransferObjects(objs);
            }
            return response;
        }

        /// <summary>
        /// Sets the sites.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public SiteResponse SetSites(SiteRequest request)
        {
            var response = new SiteResponse(request.RequestId);
            object errorMessage = null;
            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;
            // Transform customer data transfer object to customer business object
            var mapper = Mapper.FromDataTransferObject(request.Site);

            // Validate customer business rules
            if (request.Action != "Delete")
            {
                if (!mapper.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    foreach (var error in mapper.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }
            try
            {
                switch (request.Action)
                {
                    case "Insert":
                        {
                            errorMessage = SiteDao.Insert(mapper);
                            break;
                        }
                    case "Update":
                        errorMessage = SiteDao.Update(mapper);
                        break;
                    case "Delete":
                        var criteria = request.Criteria;
                        errorMessage = SiteDao.Delete(criteria.IdList);
                        break;
                }
            }
            catch (Exception)
            {
                response.Acknowledge = AcknowledgeType.Failure;
                return response;
            }
            if (errorMessage != null)
            {
                response.Acknowledge = AcknowledgeType.Failure;
                response.Message = errorMessage.ToString();
                return response;
            }
            response.Acknowledge = AcknowledgeType.Success;
            return response;
        }

        #endregion

        #region Permission

        /// <summary>
        /// Gets the permissions.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public PermissionResponse GetPermissions(PermissionRequest request)
        {
            var response = new PermissionResponse(request.RequestId);
            var criteria = request.Criteria;

            if (!ValidRequest(request, response, Validate.All))
                return response;

            if (request.LoadOptions.Contains("Permissions"))
            {
                if ((OptionType.IsPaging & request.OptionTypes) == OptionType.IsPaging)
                {
                    var totalPage = request.TotalPage;
                    var objs = PermissionDao.GetPaged(request.CurrentPage, ref totalPage);
                    response.TotalPage = totalPage;
                    response.Permissions = Mapper.ToDataTransferObjects(objs);
                }
                else
                {
                    var objs = PermissionDao.GetList();
                    response.Permissions = Mapper.ToDataTransferObjects(objs);
                }
            }
            if (request.LoadOptions.Contains("GetByUserAndSite"))
            {
                var objs = PermissionDao.GetListByUserAndSite(criteria.UserId, criteria.SiteId);
                response.Permissions = Mapper.ToDataTransferObjects(objs);
            }
            if (request.LoadOptions.Contains("Permission"))
            {
                var obj = PermissionDao.Get(criteria.Id);
                response.Permission = Mapper.ToDataTransferObject(obj);
            }
            if (request.LoadOptions.Contains("CheckExistsInRoleInSite"))
            {
                var obj = PermissionDao.CheckExistInRoleInSite(criteria.SiteId, criteria.Code, criteria.UserId);
                response.Permission = Mapper.ToDataTransferObject(obj);
            }
            return response;
        }

        /// <summary>
        /// Sets the roles.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public PermissionResponse SetPermissions(PermissionRequest request)
        {
            var response = new PermissionResponse(request.RequestId);
            object errorMessage = null;

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;
            // Transform customer data transfer object to customer business object
            var mapper = Mapper.FromDataTransferObject(request.Permission);

            // Validate customer business rules
            if (request.Action != "Delete")
            {
                if (!mapper.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    foreach (var error in mapper.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }
            try
            {
                switch (request.Action)
                {
                    case "Insert":
                        {
                            var permission = PermissionDao.Get(mapper.Code);
                            if (permission != null)
                            {
                                response.MessageCode = "PermissionExist";
                                break;
                            }
                            errorMessage = PermissionDao.Insert(mapper);
                            break;
                        }

                    case "Update":
                        errorMessage = PermissionDao.Update(mapper);
                        break;
                    case "Delete":
                        var criteria = request.Criteria;
                        errorMessage = PermissionDao.Delete(criteria.IdList);
                        break;
                }
            }
            catch (Exception e)
            {
                response.Acknowledge = AcknowledgeType.Failure;
                response.Message = e.Message;
                return response;
            }
            if (errorMessage != null)
            {
                int insertId;
                int.TryParse(errorMessage.ToString(), out insertId);
                if (insertId == 0)
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = errorMessage.ToString();
                }
            }
            response.Acknowledge = AcknowledgeType.Success;
            return response;
        }

        #endregion

        #region PermissionInSite

        /// <summary>
        /// Gets the permission in site.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public PermissionInSiteResponse GetPermissionInSite(PermissionInSiteRequest request)
        {
            var response = new PermissionInSiteResponse(request.RequestId);
            var criteria = request.Criteria;

            if (!ValidRequest(request, response, Validate.ClientTag | Validate.AccessToken))
                return response;

            if (request.LoadOptions.Contains("PermissionInSiteByPermission"))
            {
                var objs = PermissionInSiteDao.GetPermissionInSiteByPermissionId(criteria.PermissionId);
                response.PermissionInSites = Mapper.ToDataTransferObjects(objs);
            }
            if (request.LoadOptions.Contains("PermissionInSiteBySite"))
            {
                var objs = PermissionInSiteDao.GetPermissionInSiteBySiteId(criteria.SiteId);
                response.PermissionInSites = Mapper.ToDataTransferObjects(objs);
            }
            if (request.LoadOptions.Contains("PermissionInSite"))
            {
                var obj = PermissionInSiteDao.Get(criteria.PermissionId);
                response.PermissionInSite = Mapper.ToDataTransferObject(obj);
            }
            return response;
        }

        /// <summary>
        /// Sets the permission in site.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public PermissionInSiteResponse SetPermissionInSite(PermissionInSiteRequest request)
        {
            var response = new PermissionInSiteResponse(request.RequestId);
            object errorMessage = null;

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;
            // Transform customer data transfer object to customer business object
            var mappers = Mapper.FromDataTransferObjects(request.PermissionInSites);

            // Validate customer business rules
            if (request.Action != "Delete")
            {
                foreach (var mapper in mappers)
                {
                    if (!mapper.Validate())
                    {
                        response.Acknowledge = AcknowledgeType.Failure;
                        foreach (var error in mapper.ValidationErrors)
                            response.Message += error + Environment.NewLine;
                        return response;
                    }
                }

            }
            try
            {
                switch (request.Action)
                {
                    case "Insert":
                        {
                            PermissionInSiteDao.Delete(request.Criteria.PermissionId);
                            errorMessage = PermissionInSiteDao.Insert(mappers);
                            break;
                        }
                    case "Update":
                        PermissionInSiteDao.Delete(request.Criteria.PermissionId);
                        errorMessage = PermissionInSiteDao.Insert(mappers);
                        break;
                }
            }
            catch (Exception)
            {
                response.Acknowledge = AcknowledgeType.Failure;                
                return response;
            }
            if (errorMessage != null)
            {
                int insertId;
                int.TryParse(errorMessage.ToString(), out insertId);
                if (insertId == 0)
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = errorMessage.ToString();
                }
            }
            response.Acknowledge = AcknowledgeType.Success;
            return response;
        }
        #endregion

        #region Role

        /// <summary>
        /// Gets the roles.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public RoleResponse GetRoles(RoleRequest request)
        {
            var response = new RoleResponse(request.RequestId);
            var criteria = request.Criteria;

            if (!ValidRequest(request, response, Validate.All))
                return response;

            if (request.LoadOptions.Contains("Roles"))
            {
                if ((OptionType.IsPaging & request.OptionTypes) == OptionType.IsPaging)
                {
                    var totalPage = request.TotalPage;
                    var roles = RoleDao.GetPaged(request.CurrentPage, ref totalPage);
                    response.Roles = Mapper.ToDataTransferObjects(roles);
                    response.TotalPage = totalPage;
                }
                else
                {
                    if (request.LoadOptions.Contains("IsActive"))
                    {
                        var roles = RoleDao.GetRolesByIsActive(criteria.IsActive);
                        response.Roles = Mapper.ToDataTransferObjects(roles);
                    }
                    else
                    {
                        var roles = RoleDao.GetRoles();
                        response.Roles = Mapper.ToDataTransferObjects(roles);
                    }

                }
            }
            if (request.LoadOptions.Contains("RoleByUser"))
            {
                var user = UserDao.GetUser(criteria.UserId);
                var roles = Roles.GetRolesForUser(user.UserName);
                response.RolesByUsername = roles;
            }
            if (request.LoadOptions.Contains("RoleInSiteByRole"))
            {
                var roleInSites = RoleInSiteDao.GetListByRole(criteria.RoleId);
                response.RoleInSite = Mapper.ToDataTransferObjects(roleInSites);
            }
            if (request.LoadOptions.Contains("RoleInSiteBySite"))
            {
                var roleInSites = RoleInSiteDao.GetListBySite(criteria.SiteId);
                response.RoleInSite = Mapper.ToDataTransferObjects(roleInSites);
            }
            if (request.LoadOptions.Contains("Role"))
            {
                var role = RoleDao.GetRole(criteria.RoleId);
                response.Role = Mapper.ToDataTransferObject(role);
            }

            return response;
        }

        /// <summary>
        /// Sets the roles.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public RoleResponse SetRoles(RoleRequest request)
        {

            var response = new RoleResponse(request.RequestId);
            object errorMessage = null;
            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;
            // Transform customer data transfer object to customer business object
            var mapper = Mapper.FromDataTransferObject(request.Role);

            // Validate customer business rules
            if (request.Action != "Delete")
            {
                if (!mapper.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    foreach (var error in mapper.ValidationErrors)
                        response.Message += error + Environment.NewLine;

                    return response;
                }
            }
            var criteria = request.Criteria;
            try
            {
                switch (request.Action)
                {
                    case "Insert":
                        {
                            var role = RoleDao.GetRole(mapper.RoleName);
                            if (role == null)
                            {
                                Roles.CreateRole(mapper.RoleName);
                                mapper.RoleId = WebSecurity.GetUserId(mapper.RoleName);
                                errorMessage = RoleDao.UpdateRole(mapper);
                            }
                            else
                            {
                                response.MessageCode = "RoleExist";
                            }
                            break;
                        }
                    case "Update":
                        {
                            errorMessage = RoleDao.UpdateRole(mapper);
                            break;
                        }
                    case "Delete":
                        {
                            foreach (var id in criteria.IdList.Split(',').Where(x => !string.IsNullOrEmpty(x)))
                            {
                                var obj = RoleDao.GetRole(int.Parse(id));
                                if (!Roles.DeleteRole(obj.RoleName))
                                {
                                    response.MessageCode = "Exception";
                                }
                            }
                            break;
                        }
                    case "AssignToRole":
                        {
                            errorMessage = RoleInSiteDao.Insert(criteria.RoleId, Mapper.FromDataTransferObjects(request.Role.RoleInSites));
                            break;
                        }
                }
            }
            catch (Exception)
            {
                response.Acknowledge = AcknowledgeType.Failure;                
                return response;
            }
            if (errorMessage != null)
            {
                int insertId;
                int.TryParse(errorMessage.ToString(), out insertId);
                if (insertId == 0)
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = errorMessage.ToString();
                }
            }
            response.Acknowledge = AcknowledgeType.Success;
            return response;
        }

        #endregion

        #region

        /// <summary>
        /// Gets the role in sites.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public RoleInSiteResponse GetRoleInSites(RoleInSiteRequest request)
        {
            var response = new RoleInSiteResponse(request.RequestId);
            var criteria = request.Criteria;

            if (!ValidRequest(request, response, Validate.All))
                return response;

            if (request.LoadOptions.Contains("RoleInSiteByRole"))
            {

            }
            if (request.LoadOptions.Contains("PermissionInSite"))
            {

            }
            return response;
        }

        /// <summary>
        /// Sets the role in site.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public RoleInSiteResponse SetRoleInSites(RoleInSiteRequest request)
        {
            var response = new RoleInSiteResponse(request.RequestId);
            object errorMessage = null;

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;
            // Transform data transfer object to business object
            var mappers = Mapper.FromDataTransferObjects(request.RoleInSites);

            // Validate customer business rules
            if (request.Action != "Delete")
            {
                foreach (var mapper in mappers.Where(mapper => !mapper.Validate()))
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    foreach (var error in mapper.ValidationErrors)
                        response.Message += error + Environment.NewLine;
                    return response;
                }
            }
            switch (request.Action)
            {
                case "Insert":
                    {
                        var roleId = request.Criteria.RoleId;
                        errorMessage = RoleInSiteDao.Delete(roleId);
                        errorMessage = RoleInSiteDao.Insert(roleId, mappers);
                        break;
                    }
                case "Update":
                    {
                        var roleId = request.Criteria.RoleId;
                        errorMessage = RoleInSiteDao.Delete(roleId);
                        errorMessage = RoleInSiteDao.Insert(roleId, mappers);
                        break;
                    }
            }
            if (errorMessage != null)
            {
                int insertId;
                int.TryParse(errorMessage.ToString(), out insertId);
                if (insertId == 0)
                {
                    response.Acknowledge = AcknowledgeType.Failure;
                    response.Message = errorMessage.ToString();
                }
            }
            response.Acknowledge = AcknowledgeType.Success;
            return response;
        }

        #endregion

        #region User

        /// <summary>
        /// Gets the users.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public UserResponse GetUsers(UserRequest request)
        {
            var response = new UserResponse(request.RequestId);
            var criteria = request.Criteria;

            if (!ValidRequest(request, response, Validate.All))
                return response;

            if (request.LoadOptions.Contains("Users"))
            {

                if ((request.OptionTypes == OptionType.IsPaging))
                {
                    var totalPage = request.TotalPage;
                    var objs = UserDao.GetPaged(request.CurrentPage, ref totalPage);
                    response.TotalPage = totalPage;
                    response.Users = Mapper.ToDataTransferObjects(objs);
                }
                else
                {
                    var users = UserDao.GetUsers();
                    response.Users = Mapper.ToDataTransferObjects(users);
                }
            }

            if (request.LoadOptions.Contains("User"))
            {
                var user = UserDao.GetUser(criteria.Id);
                if (user != null)
                {
                    if (request.LoadOptions.Contains("IncludeRoles"))
                        user.Roles = RoleDao.GetRolesForUser(user.UserId);
                }
                response.User = Mapper.ToDataTransferObject(user);
            }
            return response;
        }

        /// <summary>
        /// Sets the users.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <returns></returns>
        public UserResponse SetUsers(UserRequest request)
        {
            var response = new UserResponse(request.RequestId);
            object errorMessage = null;

            // Validate client tag, access token, and user credentials
            if (!ValidRequest(request, response, Validate.All))
                return response;

            // Transform customer data transfer object to customer business object
            var user = Mapper.FromDataTransferObject(request.User);

            if (request.Action != "Delete")
            {
                if (!user.Validate())
                {
                    response.Acknowledge = AcknowledgeType.Failure;

                    foreach (var error in user.ValidationErrors)
                        response.Message += error + Environment.NewLine;
                    return response;
                }
            }
            try
            {
                switch (request.Action)
                {
                    case "Insert":
                        {
                            if (WebSecurity.GetUserId(user.UserName) > 0)
                            {
                                response.MessageCode = "UserExist";
                                break;
                            }
                            var userExist = UserDao.GetUser(user.Email);
                            if (userExist.Count > 0)
                            {
                                response.MessageCode = "EmailExist";
                                break;
                            }
                            WebSecurity.CreateUserAndAccount(user.UserName, user.Password, false);
                            user.UserId = WebSecurity.GetUserId(user.UserName);
                            var roles = user.Roles.Select(item => item.RoleName).ToList();
                            if (roles.Count > 0)
                                Roles.AddUserToRoles(user.UserName, roles.ToArray());
                            errorMessage = UserDao.UpdateUser(user);
                            break;
                        }

                    case "Update":
                        {
                            var roles = user.Roles.Select(item => item.RoleName).ToList();
                            var currentRoles = Roles.GetRolesForUser(user.UserName);
                            if (currentRoles.Any())
                                Roles.RemoveUserFromRoles(user.UserName, currentRoles);
                            if (roles.Count > 0)
                                Roles.AddUserToRoles(user.UserName, roles.ToArray());
                            if (!user.Password.Equals("10aaf454c194b23c9163c107b12c958b"))
                            {
                                var token = WebSecurity.GeneratePasswordResetToken(user.UserName);
                                WebSecurity.ResetPassword(token, user.Password);
                            }
                            errorMessage = UserDao.UpdateUser(user);
                            break;
                        }
                    case "ChangeUserProfile":
                        {
                            if (!user.Password.Equals("10aaf454c194b23c9163c107b12c958b"))
                            {
                                var token = WebSecurity.GeneratePasswordResetToken(user.UserName);
                                WebSecurity.ResetPassword(token, user.Password);
                            }
                            errorMessage = UserDao.ChangeUserProfile(user);
                            break;
                        }
                    case "GrantUnit":
                        {
                            errorMessage = UserDao.UpdateUser(user);
                            break;
                        }
                    case "Delete":
                        {
                            var criteria = request.Criteria;
                            foreach (var id in criteria.IdList.Split(',').Where(x => !string.IsNullOrEmpty(x)))
                            {
                                var userDelete = UserDao.GetUser(int.Parse(id));
                                var roles = Roles.GetRolesForUser(userDelete.UserName);
                                if (roles.Any())
                                    Roles.RemoveUserFromRoles(userDelete.UserName, roles);
                                if (!Membership.DeleteUser(userDelete.UserName))
                                {
                                    response.MessageCode = "Exception";
                                    break;
                                }
                            }
                            break;
                        }
                }
            }
            catch (Exception)
            {
                response.Acknowledge = AcknowledgeType.Failure;                
                return response;
            }
            if (errorMessage != null)
            {
                response.Acknowledge = AcknowledgeType.Failure;
                response.Message = errorMessage.ToString();
                return response;
            }
            response.Acknowledge = AcknowledgeType.Success;
            return response;
        }
        #endregion

        #region Primary key encryption methods. Not currently used.

        /// <summary>
        /// Encrypts internal identifier before sending it out to client.
        /// Private helper method.
        /// </summary>
        /// <param name="id">Identifier to be encrypted.</param>
        /// <param name="tableName">Database table in which identifier resides.</param>
        /// <returns>
        /// Encrypted stringified identifier.
        /// </returns>
        private string EncryptId(int id, string tableName)
        {
            var s = id.ToString(CultureInfo.InvariantCulture) + "|" + tableName;
            return Crypto.ActionEncrypt(s);
        }

        /// <summary>
        /// Decrypts identifiers that come back from client.
        /// Private helper method.
        /// </summary>
        /// <param name="sid">Stringified, encrypted identifier.</param>
        /// <returns>
        /// Internal identifier.
        /// </returns>
        private int DecryptId(string sid)
        {
            var s = Crypto.ActionDecrypt(sid);
            s = s.Substring(0, s.IndexOf("|", System.StringComparison.Ordinal));
            return int.Parse(s);
        }

        #endregion

        /// <summary>
        /// Validation options enum. Used in validation of messages.
        /// </summary>
        [Flags]
        private enum Validate
        {
            /// <summary>
            /// The client tag
            /// </summary>
            ClientTag = 0x0001,
            /// <summary>
            /// The access token
            /// </summary>
            AccessToken = 0x0002,
            /// <summary>
            /// The user credentials
            /// </summary>
            UserCredentials = 0x0004,
            /// <summary>
            /// All
            /// </summary>
            All = ClientTag | AccessToken | UserCredentials
        }
    }
}
